using System.Windows.Forms;
using NUnit.Framework;
using Rhino.Mocks;

namespace ShadeTree.Binding.Tests
{
    [TestFixture]
    public class When_binding_an_array_of_ScreenElements
    {
        #region Setup/Teardown

        [SetUp]
        public void SetUp()
        {
        }

        #endregion


        [Test]
        public void IsDirty_checks_each_IBoundScreenElement()
        {
            var mocks = new MockRepository();
            var element1 = mocks.DynamicMock<IBoundScreenElement>();
            var element2 = mocks.DynamicMock<IBoundScreenElement>();

            var binder = new ScreenBinder<ScreenBinderTarget>();

            using (mocks.Record())
            {
                Expect.Call(element1.IsDirty()).Return(true);
                Expect.Call(element2.IsDirty()).Return(false);
            }

            mocks.ReplayAll();

            binder.AddElement(element1);
                binder.AddElement(element2);

                binder.IsDirty().ShouldBeFalse();
            
        }


        [Test]
        public void IsDirty_checks_each_IBoundScreenElement_2()
        {
            var mocks = new MockRepository();
            var element1 = mocks.DynamicMock<IBoundScreenElement>();
            var element2 = mocks.DynamicMock<IBoundScreenElement>();

            var binder = new ScreenBinder<ScreenBinderTarget>();
            binder.BindToModel(new ScreenBinderTarget());

            using (mocks.Record())
            {
                Expect.Call(element1.IsDirty()).Return(true);
                Expect.Call(element2.IsDirty()).Return(false);
            }

            mocks.ReplayAll();
                binder.AddElement(element1);
                binder.AddElement(element2);

                binder.IsDirty().ShouldBeTrue();
            
        }


        [Test]
        public void Removing_an_element_by_control_calls_stop_binding_on_the_control_being_removed()
        {
            var mocks = new MockRepository();
            var element = mocks.StrictMock<IBoundScreenElement>();
            var control = new Control();

            var binder = new ScreenBinder<ScreenBinderTarget>();


            using (mocks.Record())
            {
                element.Binder = binder;
                Expect.Call(element.Control).Return(control);
                element.StopBinding();
            }

            using (mocks.Playback())
            {
                binder.AddElement(element);
                binder.RemoveElementForControl(control);
                binder.FindElementForControl(control).ShouldBeNull();
            }
        }

        [Test]
        public void When_adding_a_new_boundelement_and_the_binder_is_already_bound_call_bind_on_the_new_element()
        {
            var mocks = new MockRepository();
            var element = mocks.StrictMock<IBoundScreenElement>();

            var target = new ScreenBinderTarget();
            var binder = new ScreenBinder<ScreenBinderTarget>();
            binder.BindToModel(target);

            using (mocks.Record())
            {
                element.Binder = binder;
                element.Bind(target);
            }

            using (mocks.Playback())
            {
                binder.AddElement(element);
            }
        }


        [Test]
        public void When_ApplyChanges_is_called_on_ScreenBinder_call_all_bound_elements()
        {
            var mocks = new MockRepository();
            var element1 = mocks.StrictMock<IBoundScreenElement>();
            var element2 = mocks.StrictMock<IScreenElement>();
            var element3 = mocks.StrictMock<IBoundScreenElement>();
            var element4 = mocks.StrictMock<IScreenElement>();
            var element5 = mocks.StrictMock<IBoundScreenElement>();

            var elements = new ScreenBinder<object>();


            using (mocks.Record())
            {
                element1.Binder = element3.Binder = element5.Binder = elements;

                // I expect
                Expect.Call(element1.ApplyChanges()).Return(true);
                Expect.Call(element3.ApplyChanges()).Return(true);
                Expect.Call(element5.ApplyChanges()).Return(true);
            }

            using (mocks.Playback())
            {
                elements.AddElement(element1);
                elements.AddElement(element2);
                elements.AddElement(element3);
                elements.AddElement(element4);
                elements.AddElement(element5);

                elements.ApplyChangesToModel().ShouldBeTrue();
            }
        }


        [Test]
        public void When_ApplyChanges_is_called_on_ScreenBinder_call_all_bound_elements_and_one_element_returns_false()
        {
            var mocks = new MockRepository();
            var element1 = mocks.StrictMock<IBoundScreenElement>();
            var element2 = mocks.StrictMock<IScreenElement>();
            var element3 = mocks.StrictMock<IBoundScreenElement>();
            var element4 = mocks.StrictMock<IScreenElement>();
            var element5 = mocks.StrictMock<IBoundScreenElement>();

            var elements = new ScreenBinder<object>();
            elements.AddElement(element1);
            elements.AddElement(element2);
            elements.AddElement(element3);
            elements.AddElement(element4);
            elements.AddElement(element5);

            using (mocks.Record())
            {
                // I expect
                Expect.Call(element1.ApplyChanges()).Return(true);
                Expect.Call(element3.ApplyChanges()).Return(false);
                Expect.Call(element5.ApplyChanges()).Return(true);
            }

            elements.ApplyChangesToModel().ShouldBeFalse();
        }

        [Test]
        public void When_Bind_is_called_on_ScreenBinder_call_all_bound_elements()
        {
            var mocks = new MockRepository();
            var element1 = mocks.DynamicMock<IBoundScreenElement>();
            var element2 = mocks.DynamicMock<IScreenElement>();
            var element3 = mocks.DynamicMock<IBoundScreenElement>();
            var element4 = mocks.DynamicMock<IScreenElement>();
            var element5 = mocks.DynamicMock<IBoundScreenElement>();

            var elements = new ScreenBinder<object>();


            var bindingTarget = new object();

            using (mocks.Record())
            {
                element1.Binder = element3.Binder = element5.Binder = elements;

                // I expect
                element1.Bind(bindingTarget);
                element3.Bind(bindingTarget);
                element5.Bind(bindingTarget);
            }

            using (mocks.Playback())
            {
                elements.AddElement(element1);
                elements.AddElement(element2);
                elements.AddElement(element3);
                elements.AddElement(element4);
                elements.AddElement(element5);
                elements.BindToModel(bindingTarget);
            }
        }

        [Test]
        public void When_Reset_is_called_on_ScreenBinder_call_all_bound_elements()
        {
            var mocks = new MockRepository();
            var element1 = mocks.StrictMock<IBoundScreenElement>();
            var element2 = mocks.StrictMock<IScreenElement>();
            var element3 = mocks.StrictMock<IBoundScreenElement>();
            var element4 = mocks.StrictMock<IScreenElement>();
            var element5 = mocks.StrictMock<IBoundScreenElement>();

            var elements = new ScreenBinder<object>();

            using (mocks.Record())
            {
                element1.Binder = element3.Binder = element5.Binder = elements;

                // I expect
                element1.Reset();
                element3.Reset();
                element5.Reset();
            }

            using (mocks.Playback())
            {
                elements.AddElement(element1);
                elements.AddElement(element2);
                elements.AddElement(element3);
                elements.AddElement(element4);
                elements.AddElement(element5);

                elements.ResetToOriginalValues();
            }
        }


        [Test]
        public void When_the_ScreenState_is_updated_call_each_element()
        {
            var mocks = new MockRepository();
            var element1 = mocks.DynamicMock<IBoundScreenElement>();
            var element2 = mocks.DynamicMock<IScreenElement>();
            var element3 = mocks.DynamicMock<IBoundScreenElement>();
            var element4 = mocks.DynamicMock<IScreenElement>();
            var element5 = mocks.DynamicMock<IBoundScreenElement>();

            var elements = new ScreenBinder<object>();


            var state = new StubScreenState();

            using (mocks.Record())
            {
                element1.Binder = element3.Binder = element5.Binder = elements;

                // I expect
                element1.EnableControl(state);
                element2.EnableControl(state);
                element3.EnableControl(state);
                element4.EnableControl(state);
                element5.EnableControl(state);
            }

            using (mocks.Playback())
            {
                elements.AddElement(element1);
                elements.AddElement(element2);
                elements.AddElement(element3);
                elements.AddElement(element4);
                elements.AddElement(element5);
                elements.EnableControls(state);
            }
        }

        [Test]
        public void When_Update_is_called_on_ScreenBinder_call_all_bound_elements()
        {
            var mocks = new MockRepository();
            var element1 = mocks.DynamicMock<IBoundScreenElement>();
            var element2 = mocks.DynamicMock<IScreenElement>();
            var element3 = mocks.DynamicMock<IBoundScreenElement>();
            var element4 = mocks.DynamicMock<IScreenElement>();
            var element5 = mocks.DynamicMock<IBoundScreenElement>();

            var elements = new ScreenBinder<object>();


            using (mocks.Record())
            {
                element1.Binder = element3.Binder = element5.Binder = elements;

                // I expect
                element1.Update();
                element3.Update();
                element5.Update();
            }

            using (mocks.Playback())
            {
                elements.AddElement(element1);
                elements.AddElement(element2);
                elements.AddElement(element3);
                elements.AddElement(element4);
                elements.AddElement(element5);
                elements.UpdateScreen();
            }
        }
    }
}